package main

import (
	"fmt"
	"strconv"
	"sync"
)

var wg sync.WaitGroup

func main() {
	//go基础
	//basic()

	//go并发
	fmt.Println("--------上面是GO基础---------------下面是GO并非--------")

	//go Concurrency1()
	//
	//for i := 0; i < 10; i++ {
	//	fmt.Println("主线程")
	//	time.Sleep(500 * time.Millisecond)
	//}

	fmt.Println("--------------------并非的通道使用--------------------")
	ch := make(chan int)
	var sum int
	for i := 0; i < 5; i++ {
		go ConcurrencyChannel(ch)
		//接收通道中的数据
		sum = <-ch
		fmt.Printf("第%d次的求和：%d\n", i+1, sum)
	}

	//使用make声明一个缓冲区通道
	bufchan := make(chan int, 2)
	BufferedChannel(bufchan)
	BufferedChannel(bufchan)

	//缓冲区容量为2 上面没有接收缓冲区的数据，执行下面的代码会导致死锁
	//BufferedChannel(bufchan)

	a := <-bufchan
	fmt.Println(a)
	b := <-bufchan
	fmt.Println(b)

	//c := <-bufchan
	//fmt.Println(c)

	fmt.Println("--------------------并发中select的使用--------------------")
	//select 类似switch 会阻塞等待 等待多个通信操作结束，根据结果执行相应的case

	selectChan1 := make(chan int)
	selectChan2 := make(chan int)

	go ConcurrencyChannel(selectChan1)
	go ConcurrencyChannel(selectChan2)

	/*
	 * select 执行规则：多个channel 执行时不是谁先执行完就执行那个case，而是按照多个case的目标谁先就绪执行谁。
	 * 多个case目标都就绪则随机执行。如果都没有就绪且有default则执行default。没有default则阻塞知直到有一个case的目标就绪
	 * 如何提高某个case执行的优先级
	 * 1、使用for 死循环 + select 中不配置default的方法直到 目标case 执行后才退出循环
	 * 2、可以使用select 中default 嵌套select 的方式实现多个case时 提高某个case执行的优先级
	 */
	select {
	case a := <-selectChan1:
		fmt.Println("第一个执行结果" + strconv.Itoa(a))
	case b := <-selectChan2:
		fmt.Println("第二个执行结果" + strconv.Itoa(b))
		//default:
		//	fmt.Println("default")
	}

	/*
		 * 互斥锁 Mutex 同一时刻运行一个携程访问资源 涉及到加锁和释放锁
			 * 同步 WaitGroup 涉及到携程个数计数 在主程序中等待其它协程执行结束
	*/
	fmt.Println("--------------------并发中同步与互斥的使用--------------------")
	for i := 0; i < 5; i++ {
		/* wg.Add(非负数的整数)
		 * 每次启动一个新的协程就会增加一个计数器，传值规则 传递非负数
		 * 必须在携程启动之前使用
		 */
		wg.Add(1)
		go lockConcurrency(&wg, i)
	}
	/*
	 * 必须在主线程中使用 高诉主线程等待所有协程执行完成
	 */
	wg.Wait()
}
